package libtool65.vin;

import java.io.IOException;
import java.io.OutputStream;

public class RelocationEntry {
	final static int SEGMENT_CODE = 0x8000;
	final static int SEGMENT_ZERO = 0x0000;
	final static int SEGMENT_MASK = 0x8000;
	final static int TYPE_EXTERN = 0x0000;
	final static int TYPE_LOW = 0x2000;
	final static int TYPE_HIGH = 0x4000;
	final static int TYPE_WORD = 0x6000;
	final static int TYPE_MASK = 0x6000;
	final static int EXTERN_TYPE_LOW = 0x40;
	final static int EXTERN_TYPE_HIGH = 0x80;
	final static int EXTERN_TYPE_WORD = 0xC0;
	final static int EXTERN_TYPE_MASK = 0xC0;
	final static int ADDRESS_MASK = 0x1FFF;
	
	private int entry = TYPE_WORD;
	private int info = 0;	// low byte or extern index;
	
	public int getSize()
	{
		switch (entry & TYPE_MASK)
		{
		case TYPE_EXTERN:
			return 3;
		case TYPE_HIGH:
			return (entry & SEGMENT_MASK) == SEGMENT_ZERO ? 2 : 3;
		}
		return 2;
	}
	
	public void write(OutputStream file) throws IOException
	{
		file.write(entry & 0xff);
		file.write((entry >> 8) & 0xff);
		if (getSize() > 2)
			file.write(info & 0xff);
	}

	public void setAddress(int address) {
		entry = (entry & ~ADDRESS_MASK) | (address & ADDRESS_MASK);
	}

	public void setCodeSegment() {
		entry = (entry & ~SEGMENT_MASK) | SEGMENT_CODE; 
	}

	public void setZeroSegment() {
		entry = (entry & ~SEGMENT_MASK) | SEGMENT_ZERO; 
	}

	public void setExtern(int index) {
		entry = (entry & TYPE_MASK) | TYPE_EXTERN;
		info = index;
	}

	public void setTypeWord() {
		setType(TYPE_WORD, EXTERN_TYPE_WORD);
	}

	public void setTypeHigh(int low_byte) {
		setType(TYPE_HIGH, EXTERN_TYPE_HIGH);
		if (!isReference())
			info = low_byte;
	}

	public void setTypeLow() {
		setType(TYPE_LOW, EXTERN_TYPE_LOW);
	}

	protected void setType(int type, int extern_type) {
		if (isReference())
			info = (info & ~ EXTERN_TYPE_MASK) | extern_type;
		else
			entry = (entry & ~TYPE_MASK) | type;
	}

	protected boolean isReference() {
		return (entry & TYPE_MASK) == TYPE_EXTERN;
	}

}
